package cn.jingyuan.bee.system;

import cn.jingyuan.bee.utils.ArrayUtils;
import cn.jingyuan.bee.utils.RegExUtils;

import java.io.Serializable;

/**
 * 代表 Java Implementation 的信息。
 */
public class JavaInfo implements Serializable {

    private final String JAVA_VERSION = SystemUtils.get("java.version", false);

    private final float JAVA_VERSION_FLOAT = getJavaVersionAsFloat();

    private final int JAVA_VERSION_INT = getJavaVersionAsInt();

    private final String JAVA_VENDOR = SystemUtils.get("java.vendor", false);

    private final String JAVA_VENDOR_URL = SystemUtils.get("java.vendor.url", false);

    // 1.1--1.3 能否识别?
    private final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1");

    private final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2");

    private final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3");

    private final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4");

    private final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5");

    private final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6");

    private final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7");

    private final boolean IS_JAVA_1_8 = getJavaVersionMatches("1.8");

    private final boolean IS_JAVA_9 = getJavaVersionMatches("9");

    private final boolean IS_JAVA_10 = getJavaVersionMatches("10");

    private final boolean IS_JAVA_11 = getJavaVersionMatches("11");

    private final boolean IS_JAVA_12 = getJavaVersionMatches("12");

    /**
     * 取得当前 Java 的版本（取自系统属性：<code>java.version</code>）。
     *
     * <p>
     * 例如：Sun JDK 1.4.2：<code>"1.4.2"</code>
     *
     * @return 属性值，如果不能取得（因为 Java 安全限制）或值不存在，则返回<code>null</code>。
     */
    public final String getVersion() {
        return JAVA_VERSION;
    }

    /**
     * 取得当前 Java 的版本（取自系统属性：<code>java.version</code>）。
     *
     * <p>
     * 例如：
     *
     * <ul>
     * <li>JDK 1.2：<code>1.2f</code></li>
     * <li>JDK 1.3.1：<code>1.31f</code></li>
     * </ul>
     *
     * @return 属性值，如果不能取得（因为 Java 安全限制）或值不存在，则返回<code>0</code>。
     */
    public final float getVersionFloat() {
        return JAVA_VERSION_FLOAT;
    }

    /**
     * 取得当前 Java 的版本（取自系统属性：<code>java.version</code>），java10 及其之后的版本返回值为 4 位。
     *
     * <p>
     * 例如：
     *
     * <ul>
     * <li>JDK 1.2：<code>120</code>。</li>
     * <li>JDK 1.3.1：<code>131</code></li>
     * <li>JDK 11.0.2：<code>1102</code></li>
     * </ul>
     *
     * @return 属性值，如果不能取得（因为 Java 安全限制）或值不存在，则返回<code>0</code>。
     */
    public final int getVersionInt() {
        return JAVA_VERSION_INT;
    }

    /**
     * 取得当前Java impl.的版本的<code>float</code>值。
     *
     * @return Java 版本的<code>float</code>值或<code>0</code>
     */
    private float getJavaVersionAsFloat() {
        if (JAVA_VERSION == null) {
            return 0f;
        }

        String str = JAVA_VERSION;

        str = RegExUtils.get("^[0-9]{1,2}(\\.[0-9]{1,2})?", str, 0);

        return Float.parseFloat(str);
    }

    /**
     * 取得当前Java impl.的版本的<code>int</code>值。
     *
     * @return Java 版本的<code>int</code>值或<code>0</code>
     */
    private int getJavaVersionAsInt() {
        if (JAVA_VERSION == null) {
            return 0;
        }

        String javaVersion = RegExUtils.get("^[0-9]{1,2}(\\.[0-9]{1,2}){0,2}", JAVA_VERSION, 0);

        String[] split = javaVersion.split("\\.");
        String result = ArrayUtils.join(split, "");

        //保证java10 及其之后的版本返回的值为 4 位
        if (split[0].length() > 1) {
            result = (result + "0000").substring(0, 4);
        }

        return Integer.parseInt(result);
    }

    /**
     * 取得当前Java impl.的厂商（取自系统属性：<code>java.vendor</code>）。
     *
     * <p>
     * 例如Sun JDK 1.4.2：<code>"Sun Microsystems Inc."</code>
     *
     * @return 属性值，如果不能取得（因为 Java 安全限制）或值不存在，则返回<code>null</code>。
     */
    public final String getVendor() {
        return JAVA_VENDOR;
    }

    /**
     * 取得当前Java impl.的厂商网站的URL（取自系统属性：<code>java.vendor.url</code>）。
     *
     * <p>
     * 例如Sun JDK 1.4.2：<code>"http://java.sun.com/"</code>
     *
     * @return 属性值，如果不能取得（因为 Java 安全限制）或值不存在，则返回<code>null</code>。
     */
    public final String getVendorURL() {
        return JAVA_VENDOR_URL;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.1，则返回<code>true</code>
     */
    public final boolean isJava1_1() {
        return IS_JAVA_1_1;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.2，则返回<code>true</code>
     */
    public final boolean isJava1_2() {
        return IS_JAVA_1_2;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.3，则返回<code>true</code>
     */
    public final boolean isJava1_3() {
        return IS_JAVA_1_3;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.4，则返回<code>true</code>
     */
    public final boolean isJava1_4() {
        return IS_JAVA_1_4;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.5，则返回<code>true</code>
     */
    public final boolean isJava1_5() {
        return IS_JAVA_1_5;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.6，则返回<code>true</code>
     */
    public final boolean isJava1_6() {
        return IS_JAVA_1_6;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.7，则返回<code>true</code>
     */
    public final boolean isJava1_7() {
        return IS_JAVA_1_7;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 1.8，则返回<code>true</code>
     */
    public final boolean isJava1_8() {
        return IS_JAVA_1_8;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 9，则返回<code>true</code>
     */
    public final boolean isJava9() {
        return IS_JAVA_9;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 10，则返回<code>true</code>
     */
    public final boolean isJava10() {
        return IS_JAVA_10;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 11，则返回<code>true</code>
     */
    public final boolean isJava11() {
        return IS_JAVA_11;
    }

    /**
     * 判断当前 Java 的版本。
     *
     * <p>
     * 如果不能取得系统属性<code>java.version</code>（因为 Java 安全限制），则总是返回 <code>false</code>
     *
     * @return 如果当前 Java 版本为 12，则返回<code>true</code>
     */
    public final boolean isJava12() {
        return IS_JAVA_12;
    }

    /**
     * 匹配当前 Java 的版本。
     *
     * @param versionPrefix Java 版本前缀
     *
     * @return 如果版本匹配，则返回<code>true</code>
     */
    private boolean getJavaVersionMatches(String versionPrefix) {
        if (JAVA_VERSION == null) {
            return false;
        }

        return JAVA_VERSION.startsWith(versionPrefix);
    }

    /**
     * 判定当前 Java 的版本是否大于等于指定的版本号。
     *
     * <p>
     * 例如：
     *
     *
     * <ul>
     * <li>测试JDK 1.2：<code>isJavaVersionAtLeast(1.2f)</code></li>
     * <li>测试JDK 1.2.1：<code>isJavaVersionAtLeast(1.31f)</code></li>
     * </ul>
     *
     * @param requiredVersion 需要的版本
     *
     * @return 如果当前 Java 版本大于或等于指定的版本，则返回<code>true</code>
     */
    public final boolean isJavaVersionAtLeast(float requiredVersion) {
        return getVersionFloat() >= requiredVersion;
    }

    /**
     * 判定当前 Java 的版本是否大于等于指定的版本号。
     *
     * <p>
     * 例如：
     *
     *
     * <ul>
     * <li>测试JDK 1.2：<code>isJavaVersionAtLeast(120)</code></li>
     * <li>测试JDK 1.2.1：<code>isJavaVersionAtLeast(131)</code></li>
     * </ul>
     *
     * @param requiredVersion 需要的版本
     *
     * @return 如果当前 Java 版本大于或等于指定的版本，则返回<code>true</code>
     */
    public final boolean isJavaVersionAtLeast(int requiredVersion) {
        return getVersionInt() >= requiredVersion;
    }

    /**
     * 将Java Implementation 的信息转换成字符串。
     *
     * @return JVM impl.的字符串表示
     */
    @Override
    public final String toString() {
        StringBuilder builder = new StringBuilder();

        SystemUtils.append(builder, "Java Version:    ", getVersion());
        SystemUtils.append(builder, "Java Vendor:     ", getVendor());
        SystemUtils.append(builder, "Java Vendor URL: ", getVendorURL());

        return builder.toString();
    }

}
